home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * SuperVGA Test Library
- *
- * Copyright (C) 1993 SciTech Software
- * All rights reserved.
- *
- * Filename: $RCSfile: svgac.c $
- * Version: $Revision: 1.3 $
- *
- * Language: ANSI C
- * Environment: IBM PC (MSDOS)
- *
- * Description: Simple library to collect together the functions in the
- * SuperVGA test library for use in other C programs. The
- * support is reasonably low level, so you can do what you
- * want. The set of routines in this source file are general
- * SuperVGA routines and are independant of the video mode
- * selected.
- *
- * MUST be compiled in the large model.
- *
- * $Id: svgac.c 1.3 1993/10/22 08:58:40 kjb release $
- *
- ****************************************************************************/
-
- #include <string.h>
- #include <dos.h>
- #include <stdlib.h>
- #include "svga.h"
- #include "vesavbe.h"
-
- /*---------------------------- Global Variables ---------------------------*/
-
- #define MAXMODES 50 /* Maximum modes available in list */
-
- int maxx,maxy,memory;
- long maxcolor,defcolor;
- int maxpage,bytesperline;
- uchar redMask,greenMask,blueMask;
- int redPos,redAdjust;
- int greenPos,greenAdjust;
- int bluePos,blueAdjust;
- bool twobanks = false,extendedflipping = false,widedac = false;
- short modeList[MAXMODES];
- char OEMString[80];
-
- int oldMode; /* Old video mode number */
- bool old50Lines; /* Was old mode 80x50? */
- int curBank; /* Current read/write bank */
- int bankAdjust; /* Bank granularity adjust factor */
- long pagesize; /* Page size for current mode */
- void *bankSwitch; /* Pointer to bank switch routine */
- void *writeBank; /* Relocated write bank routine */
- void *readBank; /* Relocated read bank routine */
- void *pageFlip; /* Relocated page flip routine */
- void (*putPixel)(int x,int y,long color);
- void (*clear)(void);
-
- /*----------------------------- Implementation ----------------------------*/
-
- /* Declare all video mode dependent routines */
-
- void _putPixel16(int x,int y,long color);
- void _putPixel256(int x,int y,long color);
- void _putPixel32k(int x,int y,long color);
- void _putPixel64k(int x,int y,long color);
- void _putPixel16m(int x,int y,long color);
- void _clear16(void);
- void _clear256(void);
- void _clear32k(void);
- void _clear64k(void);
- void _clear16m(void);
-
- PRIVATE bool checkVESAPageFlip(void)
- /****************************************************************************
- *
- * Function: checkVESAPageFlip
- * Returns: True if VBE supports page flipping.
- *
- * Description: Determines if the VESA VBE supports extended page
- * flipping or not. Assume a suitable video mode has already
- * been initialised.
- *
- ****************************************************************************/
- {
- union REGS regs;
-
- regs.x.ax = 0x4F07; /* Set display start service */
- regs.x.bx = 0; /* BH := 0, BL := 0 (set display start) */
- regs.x.cx = 0; /* Leftmost pixel in line */
- regs.x.dx = 0; /* First displayed scanline */
- int86(0x10,®s,®s);
- if (regs.x.ax != 0x004F)
- return false; /* Function failed, not page flip */
-
- regs.x.ax = 0x4F07; /* Get display start service */
- regs.x.bx = 1; /* BH := 0, BL := 1 (get display start) */
- int86(0x10,®s,®s);
- if (regs.x.ax != 0x004F)
- return false; /* Function failed, not page flip */
- if (regs.h.bh != 0)
- return false;
- if (regs.x.cx != 0)
- return false;
- if (regs.x.dx != 0)
- return false;
- return true;
- }
-
- bool checkWideDAC(void)
- /****************************************************************************
- *
- * Function: checkWideDAC
- * Returns: True if 8 bit wide DAC is supported.
- *
- * Description: Tests to see if the VBE BIOS supports an 8 bit wide
- * DAC. This assumes the video card is in an appropriate
- * video mode before being called.
- *
- ****************************************************************************/
- {
- union REGS regs;
- short bits;
-
- regs.x.ax = 0x4F08; /* Set DAC service */
- regs.x.bx = 0x0800; /* BH := 8, BL := 0 (set DAC width) */
- int86(0x10,®s,®s);
- if (regs.x.ax != 0x004F)
- return false; /* Function failed, no wide dac */
- if (regs.h.bh == 6)
- return false;
- regs.x.ax = 0x4F08;
- regs.x.bx = 0x0001; /* Get DAC width (should now be 8) */
- int86(0x10,®s,®s);
- if (regs.x.ax != 0x004F)
- return false;
- bits = regs.h.bh;
- regs.x.ax = 0x4F08;
- regs.x.bx = 0x0600;
- int86(0x10,®s,®s); /* Restore to 6 bit DAC */
- if (regs.x.ax != 0x004F)
- return false;
-
- return (bits == 8);
- }
-
- PUBLIC int initSuperVGA(void)
- /****************************************************************************
- *
- * Function: initSuperVGA
- * Returns: VBE version number for the SuperVGA (0 if no SuperVGA).
- *
- * Description: Detects if a VESA VBE compliant SuperVGA is out there, and
- * initialises the library if one is. The VBE version number
- * is specified with the major version number in the high
- * byte and the minor version number in the low byte. So
- * version 1.2 is the number 0x102.
- *
- ****************************************************************************/
- {
- VgaInfoBlock vgaInfo;
- ModeInfoBlock modeInfo;
- union REGS regs;
- struct SREGS sregs;
- short *p,i;
-
- sregs.es = SEG(&vgaInfo);
- regs.x.di = OFF(&vgaInfo);
- regs.x.ax = 0x4F00;
- int86x(0x10,®s,®s,&sregs); /* Get SuperVGA information */
- if (regs.x.ax != 0x004F)
- return false;
- if (strncmp(vgaInfo.VESASignature,"VESA",4) != 0)
- return false;
-
- /* Copy relavent information from the mode block into our globals.
- * Note that the video mode list _may_ be built in the information
- * block that we have passed, so we _must_ copy this from here
- * into our our storage if we want to continue to use it. Note
- * that we filter out the mode 0x6A, which some BIOSes include as
- * well as the 0x102 mode for 800x600x16.
- */
-
- for (i = 0,p = vgaInfo.VideoModePtr; *p != -1; p++,i++) {
- if (*p != 0x6A)
- modeList[i] = *p;
- }
- modeList[i] = -1;
- memory = vgaInfo.TotalMemory * 64;
- strcpy(OEMString,vgaInfo.OEMStringPtr);
-
- /* Determine if the board supports separate read/write banks and
- * extended page flipping. Some VESA VBE's require the card to be
- * in a graphics mode for these tests to work, so we find a suitable
- * mode and use that.
- */
-
- for (p = modeList; *p != -1; p++) {
- sregs.es = SEG(&modeInfo);
- regs.x.di = OFF(&modeInfo);
- regs.x.ax = 0x4F01;
- regs.x.cx = *p;
- int86x(0x10,®s,®s,&sregs); /* Get SuperVGA mode info */
- if (regs.x.ax == 0x004F &&
- (modeInfo.MemoryModel == 3 || modeInfo.MemoryModel == 4)) {
- modeInfo.WinBAttributes &= 0x7;
- twobanks = (modeInfo.WinBAttributes == 0x3);
- setSuperVGAMode(*p);
- extendedflipping = checkVESAPageFlip();
- widedac = checkWideDAC();
- restoreMode();
- break;
- }
- }
-
- return vgaInfo.VESAVersion;
- }
-
- PRIVATE void computePageInfo(ModeInfoBlock *modeInfo,int *maxpage,
- long *pagesize)
- /****************************************************************************
- *
- * Function: computePageInfo
- * Parameters: modeInfo - Pointer to valid mode information block
- * maxpage - Number of display pages - 1
- * pagesize - Size of each logical display page in bytes
- *
- * Description: Computes the number of image pages and size of each image
- * page for a specified video mode.
- *
- ****************************************************************************/
- {
- long memsize,size;
-
- if (extendedflipping)
- memsize = memory * 1024L;
- else
- memsize = 256 * 1024L; /* Use only 256k to compute pages */
-
- size = (long)modeInfo->BytesPerScanLine * (long)modeInfo->YResolution;
- if (modeInfo->BitsPerPixel == 4) {
- /* We have a 16 color video mode, so round up the page size to
- * 8k, 16k, 32k or 64k boundaries depending on how large it is.
- */
-
- size = (size + 0x1FFFL) & 0xFFFFE000L;
- if (size != 0x2000) {
- size = (size + 0x3FFFL) & 0xFFFFC000L;
- if (size != 0x4000) {
- size = (size + 0x7FFFL) & 0xFFFF8000L;
- if (size != 0x8000)
- size = (size + 0xFFFFL) & 0xFFFF0000L;
- }
- }
- }
- else
- size = (size + 0xFFFFL) & 0xFFFF0000L;
-
- if (modeInfo->MemoryModel == memPL)
- memsize /= 4;
- if (size <= memsize)
- *maxpage = (memsize / size) - 1;
- else
- *maxpage = 0;
- *pagesize = size;
- }
-
- PUBLIC bool getSuperVGAModeInfo(int mode,int *xres,int *yres,
- int *bytesperline,int *bitsperpixel,int *memmodel,int *maxpage,
- long *pagesize)
- /****************************************************************************
- *
- * Function: getSuperVGAModeInfo
- * Parameters: mode - Mode to get information about
- * xres - Place to store x resolution
- * yres - Place to store y resolution
- * bytesperline - Bytes per scanline
- * bitsperpixel - Place to store bits per pixel (2^n colors)
- * memmodel - Memory model for mode (planar, packed etc)
- * maxpage - Number of display pages - 1
- * pagesize - Size of each logical display page in bytes
- * Returns: True if mode number was valid, false if not.
- *
- * Description: Obtains information about a specific video mode from the
- * VBE. You should use this function to find the video mode
- * you wish to set, as the new VBE 2.0 mode numbers may be
- * completely arbitrary.
- *
- ****************************************************************************/
- {
- ModeInfoBlock modeInfo;
- union REGS regs;
- struct SREGS sregs;
-
- if (mode <= 0x13) {
- /* This is a standard VGA mode, so fill in the required information
- * ourselves.
- */
-
- switch (mode) {
- case 0x0D:
- modeInfo.XResolution = 320;
- modeInfo.YResolution = 200;
- modeInfo.BytesPerScanLine = 40;
- modeInfo.BitsPerPixel = 4;
- modeInfo.MemoryModel = memPL;
- break;
- case 0x0E:
- modeInfo.XResolution = 640;
- modeInfo.YResolution = 200;
- modeInfo.BytesPerScanLine = 80;
- modeInfo.BitsPerPixel = 4;
- modeInfo.MemoryModel = memPL;
- break;
- case 0x10:
- modeInfo.XResolution = 640;
- modeInfo.YResolution = 350;
- modeInfo.BytesPerScanLine = 80;
- modeInfo.BitsPerPixel = 4;
- modeInfo.MemoryModel = memPL;
- break;
- case 0x12:
- modeInfo.XResolution = 640;
- modeInfo.YResolution = 480;
- modeInfo.BytesPerScanLine = 80;
- modeInfo.BitsPerPixel = 4;
- modeInfo.MemoryModel = memPL;
- break;
- case 0x13:
- modeInfo.XResolution = 320;
- modeInfo.YResolution = 200;
- modeInfo.BytesPerScanLine = 320;
- modeInfo.BitsPerPixel = 8;
- modeInfo.MemoryModel = memPK;
- break;
- default:
- return false;
- }
- }
- else {
- /* This is a VESA mode, so call the BIOS to get information about
- * it.
- */
-
- sregs.es = SEG(&modeInfo);
- regs.x.di = OFF(&modeInfo);
- regs.x.ax = 0x4F01;
- regs.x.cx = mode;
- int86x(0x10,®s,®s,&sregs); /* Get mode information */
- if (regs.x.ax != 0x004F)
- return false;
- if ((modeInfo.ModeAttributes & 0x1) == 0)
- return false;
- }
- *xres = modeInfo.XResolution;
- *yres = modeInfo.YResolution;
- *bytesperline = modeInfo.BytesPerScanLine;
- *memmodel = modeInfo.MemoryModel;
- *bitsperpixel = modeInfo.BitsPerPixel;
- if (*memmodel == memPK && *bitsperpixel > 8) {
- /* Support old style definitions, which some BIOS'es still use :-( */
- *memmodel = memRGB;
- switch (*bitsperpixel) {
- case 15:
- redMask = 0x1F; redPos = 10; redAdjust = 3;
- greenMask = 0x1F; greenPos = 5; greenAdjust = 3;
- blueMask = 0x1F; bluePos = 0; blueAdjust = 3;
- break;
- case 16:
- redMask = 0x1F; redPos = 11; redAdjust = 3;
- greenMask = 0x3F; greenPos = 5; greenAdjust = 2;
- blueMask = 0x1F; bluePos = 0; blueAdjust = 3;
- break;
- case 24:
- redMask = 0xFF; redPos = 16; redAdjust = 0;
- greenMask = 0xFF; greenPos = 8; greenAdjust = 0;
- blueMask = 0xFF; bluePos = 0; blueAdjust = 0;
- break;
- }
- }
- else if (*memmodel == memRGB) {
- /* Convert the 32k direct color modes of VBE 1.2+ BIOSes to
- * be recognised as 15 bits per pixel modes.
- */
-
- if (*bitsperpixel == 16 && modeInfo.RsvdMaskSize == 1)
- *bitsperpixel = 15;
-
- /* Save direct color info mask positions etc */
-
- redMask = (0xFF >> (redAdjust = 8 - modeInfo.RedMaskSize));
- redPos = modeInfo.RedFieldPosition;
- greenMask = (0xFF >> (greenAdjust = 8 - modeInfo.GreenMaskSize));
- greenPos = modeInfo.GreenFieldPosition;
- blueMask = (0xFF >> (blueAdjust = 8 - modeInfo.BlueMaskSize));
- bluePos = modeInfo.BlueFieldPosition;
- }
- if (mode == 0x13 && !extendedflipping)
- *maxpage = 0;
- else
- computePageInfo(&modeInfo,maxpage,pagesize);
- return true;
- }
-
- typedef struct {
- short writeBankLen;
- void *writeBank;
- short readBankLen;
- void *readBank;
- short newPageLen;
- void *newPage;
- } PMInfoBlock;
-
- PUBLIC bool setSuperVGAMode(int mode)
- /****************************************************************************
- *
- * Function: setSuperVGAMode
- * Parameters: mode - SuperVGA video mode to set.
- * Returns: True if the mode was set, false if not.
- *
- * Description: Attempts to set the specified video mode. This routine
- * assumes that the library and SuperVGA have been initialised
- * with the initSuperVGA() routine first.
- *
- ****************************************************************************/
- {
- ModeInfoBlock modeInfo;
- PMInfoBlock *pmInfo = (PMInfoBlock*)&modeInfo;
- union REGS regs;
- struct SREGS sregs;
- int bitsperpixel,memmodel;
-
- regs.x.ax = 0x0F00;
- int86(0x10,®s,®s);
- oldMode = regs.x.ax & 0x7F; /* Save old video mode */
- old50Lines = false; /* Default to 25 line mode */
- if (oldMode == 0x3) {
- regs.x.ax = 0x1130;
- regs.x.bx = 0;
- regs.x.dx = 0;
- int86(0x10,®s,®s);
- old50Lines = (regs.h.dl == 49);
- }
-
- regs.x.ax = 0x4F02;
- regs.x.bx = mode;
- int86(0x10,®s,®s); /* Set the video mode */
- if (regs.x.ax != 0x004F)
- return false;
-
- getSuperVGAModeInfo(mode,&maxx,&maxy,&bytesperline,&bitsperpixel,
- &memmodel,&maxpage,&pagesize);
- maxx--; maxy--;
-
- /* Now set up the vectors to the correct routines for the video
- * mode type.
- */
-
- switch (bitsperpixel) {
- case 4:
- putPixel = _putPixel16;
- clear = _clear16;
- maxcolor = defcolor = 15;
- break;
- case 8:
- putPixel = _putPixel256;
- clear = _clear256;
- maxcolor = 255;
- defcolor = 15;
- break;
- case 15:
- putPixel = _putPixel32k;
- clear = _clear32k;
- maxcolor = defcolor = 0x7FFF;
- break;
- case 16:
- putPixel = _putPixel64k;
- clear = _clear64k;
- maxcolor = defcolor = 0xFFFF;
- break;
- case 24:
- putPixel = _putPixel16m;
- clear = _clear16m;
- maxcolor = defcolor = 0xFFFFFF;
- break;
- }
-
- if (mode <= 0x13) {
- /* This is a normal VGA style mode, so we need to determine the
- * correct information for bank switching from the BIOS
- */
-
- if (mode == 0x13)
- mode = 0x101;
- else
- mode = 0x102;
- }
- sregs.es = SEG(&modeInfo);
- regs.x.di = OFF(&modeInfo);
- regs.x.ax = 0x4F01;
- regs.x.cx = mode;
- int86x(0x10,®s,®s,&sregs); /* Get mode information */
- bankAdjust = 64 / modeInfo.WinGranularity;
- curBank = -1;
- bankSwitch = modeInfo.WinFuncPtr;
-
- /* Now set up the vectors to the appropriate bank switching routines.
- * If the Universal VESA VBE is installed, we can move the bank
- * switching routines from there into our own code space for speed
- * (especially under protected mode).
- */
-
- sregs.es = SEG(&modeInfo);
- regs.x.di = OFF(&modeInfo);
- regs.x.ax = 0x4F01;
- regs.x.cx = -1;
- int86x(0x10,®s,®s,&sregs); /* Get mode information */
- writeBank = readBank = pageFlip = NULL;
- if (regs.x.ax == 0x004F && regs.x.cx == 0xCABD) {
- /* The Universal VESA VBE is there and functioning, so copy the
- * routines onto the heap and execute from there.
- */
-
- writeBank = malloc(pmInfo->writeBankLen);
- memcpy(writeBank,pmInfo->writeBank,pmInfo->writeBankLen);
- if (pmInfo->readBankLen > 0) {
- readBank = malloc(pmInfo->readBankLen);
- memcpy(readBank,pmInfo->readBank,pmInfo->readBankLen);
- }
- pageFlip = malloc(pmInfo->newPageLen);
- memcpy(pageFlip,pmInfo->newPage,pmInfo->newPageLen);
- }
-
- return true;
- }
-
- PUBLIC void restoreMode(void)
- /****************************************************************************
- *
- * Function: restoreMode
- *
- * Description: Restore the previous video mode in use before the SuperVGA
- * mode was set. This routine will also restore the 50 line
- * display mode if this mode was previously set.
- *
- ****************************************************************************/
- {
- union REGS regs;
-
- regs.x.ax = oldMode;
- int86(0x10,®s,®s); /* Set the old video mode */
- if (old50Lines) {
- regs.x.ax = 0x1112;
- regs.x.bx = 0;
- int86(0x10,®s,®s); /* Restore 50 line mode */
- }
- }
-
- void setSuperVGADisplayStart(int x,int y)
- /****************************************************************************
- *
- * Function: setDisplayStart
- * Parameters: x,y - Position of the first pixel to display
- *
- * Description: Sets the new starting display position to implement
- * hardware scrolling.
- *
- ****************************************************************************/
- {
- union REGS regs;
-
- if (extendedflipping) {
- regs.x.ax = 0x4F07;
- regs.x.bx = 0x0000;
- regs.x.cx = x;
- regs.x.dx = y;
- int86(0x10,®s,®s);
- }
- }
-
- long rgbColor(uchar r,uchar g,uchar b)
- /****************************************************************************
- *
- * Function: rgbColor
- *
- * Returns: Value representing the color. The value is converted from
- * 24 bit RGB space into the appropriate color for the
- * video mode.
- *
- ****************************************************************************/
- {
- return ((long)((r >> redAdjust) & redMask) << redPos)
- | ((long)((g >> greenAdjust) & greenMask) << greenPos)
- | ((long)((b >> blueAdjust) & blueMask) << bluePos);
- }
-
- PUBLIC void line(int x1,int y1,int x2,int y2,long color)
- /****************************************************************************
- *
- * Function: line
- * Parameters: x1,y1 - First endpoint of line
- * x2,y2 - Second endpoint of line
- * color - Color to draw the line in
- *
- * Description: Scan convert a line segment using the MidPoint Digital
- * Differential Analyser algorithm.
- *
- ****************************************************************************/
- {
- int d; /* Decision variable */
- int dx,dy; /* Dx and Dy values for the line */
- int Eincr,NEincr; /* Decision variable increments */
- int yincr; /* Increment for y values */
- int t; /* Counters etc. */
-
- dx = ABS(x2 - x1);
- dy = ABS(y2 - y1);
-
- if (dy <= dx) {
-
- /* We have a line with a slope between -1 and 1
- *
- * Ensure that we are always scan converting the line from left to
- * right to ensure that we produce the same line from P1 to P0 as the
- * line from P0 to P1.
- */
-
- if (x2 < x1) {
- t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
- t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
- }
-
- if (y2 > y1)
- yincr = 1;
- else
- yincr = -1;
-
- d = 2*dy - dx; /* Initial decision variable value */
- Eincr = 2*dy; /* Increment to move to E pixel */
- NEincr = 2*(dy - dx); /* Increment to move to NE pixel */
-
- putPixel(x1,y1,color); /* Draw the first point at (x1,y1) */
-
- /* Incrementally determine the positions of the remaining pixels
- */
-
- for (x1++; x1 <= x2; x1++) {
- if (d < 0) {
- d += Eincr; /* Choose the Eastern Pixel */
- }
- else {
- d += NEincr; /* Choose the North Eastern Pixel */
- y1 += yincr; /* (or SE pixel for dx/dy < 0!) */
- }
- putPixel(x1,y1,color); /* Draw the point */
- }
- }
- else {
-
- /* We have a line with a slope between -1 and 1 (ie: includes
- * vertical lines). We must swap our x and y coordinates for this.
- *
- * Ensure that we are always scan converting the line from left to
- * right to ensure that we produce the same line from P1 to P0 as the
- * line from P0 to P1.
- */
-
- if (y2 < y1) {
- t = x2; x2 = x1; x1 = t; /* Swap X coordinates */
- t = y2; y2 = y1; y1 = t; /* Swap Y coordinates */
- }
-
- if (x2 > x1)
- yincr = 1;
- else
- yincr = -1;
-
- d = 2*dx - dy; /* Initial decision variable value */
- Eincr = 2*dx; /* Increment to move to E pixel */
- NEincr = 2*(dx - dy); /* Increment to move to NE pixel */
-
- putPixel(x1,y1,color); /* Draw the first point at (x1,y1) */
-
- /* Incrementally determine the positions of the remaining pixels
- */
-
- for (y1++; y1 <= y2; y1++) {
- if (d < 0) {
- d += Eincr; /* Choose the Eastern Pixel */
- }
- else {
- d += NEincr; /* Choose the North Eastern Pixel */
- x1 += yincr; /* (or SE pixel for dx/dy < 0!) */
- }
- putPixel(x1,y1,color); /* Draw the point */
- }
- }
- }
-
- PUBLIC void writeText(int x,int y,uchar *str,long color)
- /****************************************************************************
- *
- * Function: writeText
- * Parameters: x,y - Position to begin drawing string at
- * str - String to draw
- *
- * Description: Draws a string using the BIOS 8x16 video font by plotting
- * each pixel in the characters individually. This should
- * work for all video modes.
- *
- ****************************************************************************/
- {
- uchar byte;
- int i,j,k,length,ch;
- uchar *font;
-
- font = getFontVec();
- length = strlen(str);
- for (k = 0; k < length; k++) {
- ch = str[k];
- for (j = 0; j < 16; j++) {
- byte = *(font + ch * 16 + j);
- for (i = 0; i < 8; i++) {
- if ((byte & 0x80) != 0)
- putPixel(x+i,y+j,color);
- byte <<= 1;
- }
- }
- x += 8;
- }
- }
-